/*
 * Fichier : Dessin.java
 * Créé le : 11 mars 2007.
 * Modifié : 15 avril 2012.
 * Auteurs : Sébastien ESTIENNE.
 * SiteWeb : http://www.prog-info.org/
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

package chapitre12.dessin;



import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.text.NumberFormat;
import java.util.ArrayList;

import javax.swing.Box;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JColorChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JToggleButton;



/**
 * <p>Classe de mini programme de dessin.</p> bug : gris qui reste, et forme en gris correspond
 * pas!
 * @author Sébastien ESTIENNE.
 */
public class Dessin extends JFrame implements MouseListener, MouseMotionListener
{
   /**
    * <p>Serial version UID.</p>
    */
   private static final long serialVersionUID = 1L;

   /** Panneau contenant les 2 boites d'outils de dessin. */
   private JPanel panneauOutils;

   /** Première boite contenant les outils de dessin. */
   private Box boiteOutils1;

   /** Seconde boite contenant les outils de dessin. */
   private Box boiteOutils2;

   /** Etiquette de barre d'état. */
   private JLabel labelEtat;

   /** Panneau pour le dessin. */
   private PanneauDessin panneauDessin;

   /** Le bouton permettant de dessiner un rectangle. */
   private JToggleButton boutonRectangle;

   /** Le bouton permettant de dessiner un rectangle plein. */
   private JToggleButton boutonRectanglePlein;

   /** Le bouton permettant de dessiner un ovale. */
   private JToggleButton boutonOvale;

   /** Le bouton permettant de dessiner un ovale plein. */
   private JToggleButton boutonOvalePlein;

   /** Le bouton permettant de dessiner un rectangle arrondi. */
   private JToggleButton boutonRectArrondi;

   /** Le bouton permettant de dessiner un rectangle arrondi plein. */
   private JToggleButton boutonRectArrondiPlein;

   /** Le bouton permettant de dessiner une ligne. */
   private JToggleButton boutonLigne;

   /** Le bouton permettant de dessiner du texte. */
   private JToggleButton boutonTexte;

   /** Le bouton permettant d'effacer la zone de dessin. */
   private JToggleButton boutonGomme;

   /** Le bouton de changement de couleur. */
   private JButton boutonCouleur;

   /** La liste des formes. */
   private ArrayList<Forme> formes;

   /** Couleur courante. */
   private Color couleurCourante;

   /** Forme courante. */
   private Forme formeCourante;

   /** Bouton courant. */
   private JToggleButton boutonCourant;

   /** Coordonnées en x de pression du click. */
   private int x1;

   /** Coordonnées en y de pression du click. */
   private int y1;

   /** Coordonnées en x de la souris (drag). */
   private int x2;

   /** Coordonnées en y de la souris (drag). */
   private int y2;


   /**
    * <p>Constructeur initialisant la fenêtre.</p>
    */
   public Dessin()
   {
      super("Dessin");

      // Initialisation de la liste des formes.
      this.formes = new ArrayList<Forme>();

      // Initialisation de la couleur courante.
      this.couleurCourante = Color.BLACK;

      // Initialisation de la forme courante.
      this.formeCourante = null;

      // Conteneur.
      Container conteneur = getContentPane();

      // Change le gestionnaire de canvas.
      conteneur.setLayout(new BorderLayout(3, 3));

      // Initialisation de l'étiquette Etat.
      this.labelEtat = new JLabel("X: Y:");
      this.labelEtat.setEnabled(false);
      conteneur.add(this.labelEtat, BorderLayout.SOUTH);

      // Initialisation du panneau de dessin.
      this.panneauDessin = new PanneauDessin();
      conteneur.add(this.panneauDessin, BorderLayout.CENTER);

      // Initialisation du panneau des outils de dessin.
      this.panneauOutils = new JPanel();
      this.panneauOutils.setLayout(new FlowLayout());
      conteneur.add(this.panneauOutils, BorderLayout.WEST);

      // Initialisation de la première boite d'outils.
      this.boiteOutils1 = Box.createVerticalBox();
      this.boiteOutils1.add(Box.createVerticalStrut(5));

      // Initialisation de la deuxième boite d'outils.
      this.boiteOutils2 = Box.createVerticalBox();
      this.boiteOutils2.add(Box.createVerticalStrut(5));

      // Bouton rectangle.
      this.boutonRectangle = new JToggleButton();
      this.boutonRectangle.setIcon(new ImageIcon(getClass().getResource("images/rectangle.png")));
      this.boutonRectangle.setFocusable(false);
      this.boutonRectangle.setMargin(new Insets(0, 0, 0, 0));
      this.boutonRectangle.setToolTipText("Rectangle");
      this.boiteOutils1.add(this.boutonRectangle);
      this.boiteOutils1.add(Box.createVerticalStrut(5));
      this.boutonRectangle.addActionListener(new ActionListener()
      {
         public void actionPerformed(ActionEvent e)
         {
            if(Dessin.this.boutonCourant != null)
            {
               Dessin.this.boutonCourant.setSelected(false);
            }

            if(Dessin.this.boutonCourant == (JToggleButton) e.getSource())
            {
               Dessin.this.formeCourante = null;
               Dessin.this.boutonCourant = null;
            }
            else
            {
               Dessin.this.formeCourante = new Rectangle();
               Dessin.this.boutonCourant = (JToggleButton) e.getSource();
            }
         }
      });

      // Bouton rectangle plein.
      this.boutonRectanglePlein = new JToggleButton();
      this.boutonRectanglePlein.setIcon(new ImageIcon(getClass().getResource(
            "images/rectanglePlein.png")));
      this.boutonRectanglePlein.setFocusable(false);
      this.boutonRectanglePlein.setMargin(new Insets(0, 0, 0, 0));
      this.boutonRectanglePlein.setToolTipText("Rectangle plein");
      this.boiteOutils2.add(this.boutonRectanglePlein);
      this.boiteOutils2.add(Box.createVerticalStrut(5));
      this.boutonRectanglePlein.addActionListener(new ActionListener()
      {
         public void actionPerformed(ActionEvent e)
         {
            if(Dessin.this.boutonCourant != null)
            {
               Dessin.this.boutonCourant.setSelected(false);
            }
            if(Dessin.this.boutonCourant == (JToggleButton) e.getSource())
            {
               Dessin.this.formeCourante = null;
               Dessin.this.boutonCourant = null;
            }
            else
            {
               Dessin.this.formeCourante = new Rectangle();
               Dessin.this.formeCourante.setRemplissage(true);
               Dessin.this.boutonCourant = (JToggleButton) e.getSource();
            }
         }
      });

      // Bouton rectangle arrondi.
      this.boutonRectArrondi = new JToggleButton();
      this.boutonRectArrondi
            .setIcon(new ImageIcon(getClass().getResource("images/rectArrondi.png")));
      this.boutonRectArrondi.setFocusable(false);
      this.boutonRectArrondi.setMargin(new Insets(0, 0, 0, 0));
      this.boutonRectArrondi.setToolTipText("Rectangle arrondi");
      this.boiteOutils1.add(this.boutonRectArrondi);
      this.boiteOutils1.add(Box.createVerticalStrut(5));
      this.boutonRectArrondi.addActionListener(new ActionListener()
      {
         public void actionPerformed(ActionEvent e)
         {
            if(Dessin.this.boutonCourant != null)
            {
               Dessin.this.boutonCourant.setSelected(false);
            }

            if(Dessin.this.boutonCourant == (JToggleButton) e.getSource())
            {
               Dessin.this.formeCourante = null;
               Dessin.this.boutonCourant = null;
            }
            else
            {
               Dessin.this.formeCourante = new RectangleArrondi();
               Dessin.this.boutonCourant = (JToggleButton) e.getSource();
            }
         }
      });

      // Bouton rectangle arrondi plein.
      this.boutonRectArrondiPlein = new JToggleButton();
      this.boutonRectArrondiPlein.setIcon(new ImageIcon(getClass().getResource(
            "images/rectArrondiPlein.png")));
      this.boutonRectArrondiPlein.setFocusable(false);
      this.boutonRectArrondiPlein.setMargin(new Insets(0, 0, 0, 0));
      this.boutonRectArrondiPlein.setToolTipText("Rectangle arrondi plein");
      this.boiteOutils2.add(this.boutonRectArrondiPlein);
      this.boiteOutils2.add(Box.createVerticalStrut(5));
      this.boutonRectArrondiPlein.addActionListener(new ActionListener()
      {
         public void actionPerformed(ActionEvent e)
         {
            if(Dessin.this.boutonCourant != null)
            {
               Dessin.this.boutonCourant.setSelected(false);
            }

            if(Dessin.this.boutonCourant == (JToggleButton) e.getSource())
            {
               Dessin.this.formeCourante = null;
               Dessin.this.boutonCourant = null;
            }
            else
            {
               Dessin.this.formeCourante = new RectangleArrondi();
               Dessin.this.formeCourante.setRemplissage(true);
               Dessin.this.boutonCourant = (JToggleButton) e.getSource();
            }
         }
      });

      // Bouton cercle.
      this.boutonOvale = new JToggleButton();
      this.boutonOvale.setIcon(new ImageIcon(getClass().getResource("images/cercle.png")));
      this.boutonOvale.setFocusable(false);
      this.boutonOvale.setMargin(new Insets(0, 0, 0, 0));
      this.boutonOvale.setToolTipText("Ovale");
      this.boiteOutils1.add(this.boutonOvale);
      this.boiteOutils1.add(Box.createVerticalStrut(5));
      this.boutonOvale.addActionListener(new ActionListener()
      {
         public void actionPerformed(ActionEvent e)
         {
            if(Dessin.this.boutonCourant != null)
            {
               Dessin.this.boutonCourant.setSelected(false);
            }

            if(Dessin.this.boutonCourant == (JToggleButton) e.getSource())
            {
               Dessin.this.formeCourante = null;
               Dessin.this.boutonCourant = null;
            }
            else
            {
               Dessin.this.formeCourante = new Ovale();
               Dessin.this.boutonCourant = (JToggleButton) e.getSource();
            }
         }
      });

      // Bouton cercle plein.
      this.boutonOvalePlein = new JToggleButton();
      this.boutonOvalePlein
            .setIcon(new ImageIcon(getClass().getResource("images/cerclePlein.png")));
      this.boutonOvalePlein.setFocusable(false);
      this.boutonOvalePlein.setMargin(new Insets(0, 0, 0, 0));
      this.boutonOvalePlein.setToolTipText("Ovale plein");
      this.boiteOutils2.add(this.boutonOvalePlein);
      this.boiteOutils2.add(Box.createVerticalStrut(5));
      this.boutonOvalePlein.addActionListener(new ActionListener()
      {
         public void actionPerformed(ActionEvent e)
         {
            if(Dessin.this.boutonCourant != null)
            {
               Dessin.this.boutonCourant.setSelected(false);
            }

            if(Dessin.this.boutonCourant == (JToggleButton) e.getSource())
            {
               Dessin.this.formeCourante = null;
               Dessin.this.boutonCourant = null;
            }
            else
            {
               Dessin.this.formeCourante = new Ovale();
               Dessin.this.formeCourante.setRemplissage(true);
               Dessin.this.boutonCourant = (JToggleButton) e.getSource();
            }
         }
      });

      // Bouton ligne.
      this.boutonLigne = new JToggleButton();
      this.boutonLigne.setIcon(new ImageIcon(getClass().getResource("images/ligne.png")));
      this.boutonLigne.setFocusable(false);
      this.boutonLigne.setMargin(new Insets(0, 0, 0, 0));
      this.boutonLigne.setToolTipText("Ligne");
      this.boiteOutils1.add(this.boutonLigne);
      this.boiteOutils1.add(Box.createVerticalStrut(5));
      this.boutonLigne.addActionListener(new ActionListener()
      {
         public void actionPerformed(ActionEvent e)
         {
            if(Dessin.this.boutonCourant != null)
            {
               Dessin.this.boutonCourant.setSelected(false);
            }

            if(Dessin.this.boutonCourant == (JToggleButton) e.getSource())
            {
               Dessin.this.formeCourante = null;
               Dessin.this.boutonCourant = null;
            }
            else
            {
               Dessin.this.formeCourante = new Ligne();
               Dessin.this.boutonCourant = (JToggleButton) e.getSource();
            }
         }
      });

      // Bouton texte.
      this.boutonTexte = new JToggleButton();
      this.boutonTexte.setIcon(new ImageIcon(getClass().getResource("images/texte.png")));
      this.boutonTexte.setFocusable(false);
      this.boutonTexte.setMargin(new Insets(0, 0, 0, 0));
      this.boutonTexte.setToolTipText("Ligne libre");
      this.boiteOutils2.add(this.boutonTexte);
      this.boiteOutils2.add(Box.createVerticalStrut(5));
      this.boutonTexte.addActionListener(new ActionListener()
      {
         public void actionPerformed(ActionEvent e)
         {
            if(Dessin.this.boutonCourant != null)
            {
               Dessin.this.boutonCourant.setSelected(false);
            }

            if(Dessin.this.boutonCourant == (JToggleButton) e.getSource())
            {
               Dessin.this.formeCourante = null;
               Dessin.this.boutonCourant = null;
            }
            else
            {
               Dessin.this.formeCourante = new Texte();
               Dessin.this.boutonCourant = (JToggleButton) e.getSource();
            }
         }
      });

      // Bouton couleur.
      this.boutonCouleur = new JButton();
      this.boutonCouleur.setFocusable(false);
      this.boutonCouleur.setMargin(new Insets(8, 8, 8, 8));
      this.boutonCouleur.setToolTipText("Changer de couleur");
      this.boutonCouleur.setBackground(Dessin.this.couleurCourante);
      this.boiteOutils1.add(this.boutonCouleur);
      this.boutonCouleur.addActionListener(new ActionListener()
      {
         public void actionPerformed(ActionEvent e)
         {
            Dessin.this.couleurCourante = JColorChooser.showDialog(Dessin.this, "Couleur",
                  Dessin.this.couleurCourante);
            Dessin.this.boutonCouleur.setBackground(Dessin.this.couleurCourante);
         }
      });

      // Bouton gomme.
      this.boutonGomme = new JToggleButton();
      this.boutonGomme.setIcon(new ImageIcon(getClass().getResource("images/gomme.png")));
      this.boutonGomme.setFocusable(false);
      this.boutonGomme.setMargin(new Insets(0, 0, 0, 0));
      this.boutonGomme.setToolTipText("Effacer tout");
      this.boiteOutils2.add(this.boutonGomme);
      this.boutonGomme.addActionListener(new ActionListener()
      {
         public void actionPerformed(ActionEvent e)
         {
            Dessin.this.formes.clear();
            Dessin.this.repaint();
         }
      });

      // Ajoute les boites d'outils.
      this.panneauOutils.add(this.boiteOutils1);
      this.panneauOutils.add(this.boiteOutils2);

      // Evénements souris.
      this.panneauDessin.addMouseListener(this);
      this.panneauDessin.addMouseMotionListener(this);

      // Propriétés de la fenêtre.
      setLocation(50, 50);
      setSize(400, 300);
      setVisible(true);
      setResizable(true);
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
   }


   /**
    * <p>Commence l'exécution du programme.</p>
    * @param args Les paramètres de la ligne de commande.
    */
   public static void main(String[] args)
   {
      new Dessin();
   }


   /**
    * <p>Invoqué lorsque le bouton de la souris a été cliqué sur le composant.</p>
    * @param e un événement qui indique qu'une action de souris s'est produite dans le composant.
    */
   public void mouseClicked(MouseEvent e)
   {
      // Ne fait rien.
   }


   /**
    * <p>Invoqué lorsque la souris entre dans le composant.</p>
    * @param e un événement qui indique qu'une action de souris s'est produite dans le composant.
    */
   public void mouseEntered(MouseEvent e)
   {
      // Ne fait rien.
   }


   /**
    * <p>Invoqué lorsque la souris quitte le composant.</p>
    * @param e un événement qui indique qu'une action de souris s'est produite dans le composant.
    */
   public void mouseExited(MouseEvent e)
   {
      // Ne fait rien.
   }


   /**
    * <p>Invoqué lorsque le bouton de la souris est pressé dans le composant.</p>
    * @param e un événement qui indique qu'une action de souris s'est produite dans le composant.
    */
   public void mousePressed(MouseEvent e)
   {
      if(this.formeCourante == null)
      {
         return;
      }

      // Enregistre les coordonnées du premier click.
      this.x1 = e.getX();
      this.y1 = e.getY();

      // Enregistre la position de la forme.
      this.formeCourante.setPosition1(this.x1, this.y1);
   }


   /**
    * <p>Invoqué lorsque le bouton de la souris est relâché dans le composant.</p>
    * @param e un événement qui indique qu'une action de souris s'est produite dans le composant.
    */
   public void mouseReleased(MouseEvent e)
   {
      if(this.formeCourante == null)
      {
         return;
      }

      // Demande le texte à afficher.
      if(this.formeCourante instanceof Texte)
      {
         String resTexte = JOptionPane.showInputDialog(this, "Texte");
         if(resTexte != null)
         {
            ((Texte) this.formeCourante).setTexte(resTexte);
         }
      }

      // Change la couleur de la forme.
      this.formeCourante.setCouleur(this.couleurCourante);

      // Ajoute un clone de la forme.
      this.formes.add((Forme) this.formeCourante.clone());

      // Réinitialise la forme.
      this.formeCourante.setPosition1(0, 0);
      this.formeCourante.setPosition2(0, 0);

      // Redessine.
      this.panneauDessin.repaint();
   }


   /**
    * <p>Invoqué lorsque le bouton de la souris est pressé et que la souris bouge dans le
    * composant.</p>
    * @param e un événement qui indique qu'une action de souris s'est produite dans le composant.
    */
   public void mouseDragged(MouseEvent e)
   {
      if(this.formeCourante == null || this.formeCourante instanceof Texte)
      {
         return;
      }

      // Enregistre les coordonnées du second click.
      this.x2 = e.getX();
      this.y2 = e.getY();

      if(this.formeCourante instanceof Ligne)
      {
         // Enregistre le deuxième point définissant la droite.
         this.formeCourante.setPosition2(this.x2, this.y2);

         // Met à jour la barre d'état.
         NumberFormat f = NumberFormat.getInstance();
         f.setMaximumFractionDigits(2);
         this.labelEtat.setText("P1("
               + this.x1
               + ", "
               + this.y1
               + ") ; P2("
               + this.x2
               + ", "
               + this.y2
               + ") Longueur: "
               + f.format(Math
                     .sqrt(Math.pow(this.x2 - this.x1, 2) + Math.pow(this.y2 - this.y1, 2))));
      }
      else
      {
         // Met à jour la position et les dimensions de la forme.
         int xx1, yy1, xx2, yy2;
         if(this.x1 < this.x2)
         {
            xx1 = this.x1;
            xx2 = this.x2;
         }
         else
         {
            xx1 = this.x2;
            xx2 = this.x1;
         }
         if(this.y1 < this.y2)
         {
            yy1 = this.y1;
            yy2 = this.y2;
         }
         else
         {
            yy1 = this.y2;
            yy2 = this.y1;
         }
         this.formeCourante.setPosition1(xx1, yy1);
         this.formeCourante.setPosition2(xx2, yy2);

         // Met à jour la barre d'état.
         this.labelEtat.setText("Pos(" + this.formeCourante.getX1() + ", "
               + this.formeCourante.getY2() + ") ; Longueur: "
               + (this.formeCourante.getX2() - this.formeCourante.getX1()) + "; Hauteur: "
               + (this.formeCourante.getY2() - this.formeCourante.getY1()));
      }

      // Redessine.
      this.panneauDessin.repaint();
   }


   /**
    * <p>Invoqué lorsque la souris bouge dans le composant.</p>
    * @param e un événement qui indique qu'une action de souris s'est produite dans le composant.
    */
   public void mouseMoved(MouseEvent e)
   {
      this.labelEtat.setText("X : " + e.getX() + " ; Y : " + e.getY());
   }

   /**
    * <p>Le panneau de dessin.</p>
    * @author Sébastien ESTIENNE.
    */
   protected class PanneauDessin extends JPanel
   {
      /**
       * <p>Serial version UID.</p>
       */
      private static final long serialVersionUID = 1L;


      /**
       * <p>Constructeur par défaut du panneau de dessin.</p>
       */
      public PanneauDessin()
      {
         super();

         // Change la couleur de fond du panneau de dessin.
         setBackground(Color.WHITE);

         // Change le curseur du panneau de dessin.
         setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
      }


      /**
       * <p>Dessine le panneau de dessin.</p>
       * @param g Le contexte graphique.
       */
      @Override
      public void paint(Graphics g)
      {
         super.paint(g);

         // Dessine un aperçu de la forme que l'utilisateur est en train de créer.
         if(Dessin.this.formeCourante != null)
         {
            Dessin.this.formeCourante.apercu(g);
         }

         // Dessine les formes.
         for(int i = 0; i < Dessin.this.formes.size(); i++)
         {
            Dessin.this.formes.get(i).dessiner(g);
         }
      }
   }
}
